#pragma once

#include "Business/IMarketHandler.h"
#include "Business/IDealingHandler.h"
class Market;
class RequestTimeout;
class Dealing;
class Trade;
struct Command;
class Customer;
struct PendingMarket;


class Business : public IMarketHandler, public IDealingHandler
{
public:
	Business(Customer& customer)
	:m_customer(customer)
	{
		static int s_id = 0;
		m_id = ++s_id;
	}
	virtual ~Business() = 0 {}
	
	int GetId() const { return m_id; }
	Customer& GetCustomer() const { return m_customer; }

	Contracts const& GetContracts() const 
	{
		return m_contracts;
	}

	void OnPendingMarket(PendingMarket const& pendingMarket)
	{
		OnBefore();
		DoOnPendingMarket(pendingMarket);
		OnAfter();
	}

	void OnInit()
	{
		OnBefore();
		DoOnInit();
		OnAfter();
	}

	void OnTimeout(RequestTimeout const& timeout)
	{
		OnBefore();
		DoOnTimeout(timeout);
		OnAfter();
	}

	void OnCommand(Command const& command)
	{
		OnBefore();
		DoOnCommand(command);
		OnAfter();
	}
	void OnExchangeStatus(int exchangeStatus)
	{
		OnBefore();
		DoOnExchangeStatus(exchangeStatus);
		OnAfter();
	}
protected:
	void AddContract(int contract)
	{
		m_contracts.push_back(contract);
	}
private:
	virtual void OnBefore() {}
	virtual void OnAfter() {}

	virtual void DoOnInit() = 0;
	virtual void DoOnMarket(Market const& market) = 0;
	virtual void DoOnPendingMarket(PendingMarket const& pendingMarket) = 0;
	virtual void DoOnDealing(Dealing const& dealing) = 0;
	virtual void DoOnTimeout(RequestTimeout const& requestTimeout) = 0;
	virtual void DoOnTrade(Trade const& trade) = 0;
	virtual void DoOnCommand(Command const& command) = 0;
	virtual void DoOnExchangeStatus(int exchangeStatus) = 0;

	int m_id;
	Contracts m_contracts;
	Customer& m_customer;
};

template<class ConcreteBusiness>
class AutoUpdateUIBusiness : public Business 
{
protected:
	class AutoSnapshotNotifier
	{
	public:
		AutoSnapshotNotifier(ConcreteBusiness& business)
			:m_business(business),m_snapshot(business.GetSnapshot())
		{
		}
		~AutoSnapshotNotifier()
		{
			ConcreteBusiness::Snapshot snapshot = m_business.GetSnapshot();
			if (snapshot != m_snapshot)
			{
				m_business.UpdateUI(snapshot);
			}
		}
	private:
		typename ConcreteBusiness& m_business;
		typename ConcreteBusiness::Snapshot m_snapshot;
	};
public:
	AutoUpdateUIBusiness(Customer& customer)
		:Business(customer)
	{
	}
};